// 读取配置文件
package fgin

import (
	"encoding/json"

	"github.com/spf13/viper"
)

type Config struct {
	ServiceName           string         `yaml:"service_name" mapstructure:"service_name"`
	Tag                   string         `yaml:"tag" mapstructure:"tag"`
	NetType               string         `yaml:"net_type" mapstructure:"net_type"`
	ServiceWeight         int            `yaml:"service_weight" mapstructure:"service_weight"`
	Ip                    string         `yaml:"ip" mapstructure:"ip"`
	Port                  int            `yaml:"port" mapstructure:"port"`
	HttpPort              int            `yaml:"http_port" mapstructure:"http_port"`
	GrpcPort              int            `yaml:"grpc_port" mapstructure:"grpc_port"`
	Env                   string         `yaml:"env" mapstructure:"env"`
	Timeout               int            `yaml:"time_out" mapstructure:"time_out"`                               // 请求超时时间，单位ms
	DisableRequestTimeout bool           `yaml:"disable_request_timeout" mapstructure:"disable_request_timeout"` // 禁止继承上游服务耗时 默认不禁止
	RateLimiter           bool           `yaml:"rate_limiter" mapstructure:"rate_limiter"`                       // 限流器是否开启
	CircuitBreaker        bool           `yaml:"circuit_breaker" mapstructure:"circuit_breaker"`                 // 熔断器是否开启
	Validator             string         `yaml:"validator" mapstructure:"validator"`                             // 独立校验器配置
	DisablePing           bool           `yaml:"disable_ping" mapstructure:"disable_ping"`                       // 是否不初始化默认ping接口
	Log                   Log            `yaml:"log" mapstructure:"log"`
	Auth                  Auth           `yaml:"auth" mapstructure:"auth"`
	Mysql                 []Mysql        `yaml:"mysql" mapstructure:"mysql"`
	GormLog               GormLog        `yaml:"gorm_log" mapstructure:"gorm_log"`
	Redis                 []Redis        `yaml:"redis" mapstructure:"redis"`
	Consul                Consul         `yaml:"consul" mapstructure:"consul"`
	Jaeger                Jaeger         `yaml:"jaeger" mapstructure:"jaeger"`
	Rabbitmq              []Rabbitmq     `yaml:"rabbitmq" mapstructure:"rabbitmq"`
	GrpcClient            []GrpcClient   `yaml:"grpc_client" mapstructure:"grpc_client"`
	Cors                  Cors           `yaml:"cors" mapstructure:"cors"`
	Prometheus            Prometheus     `yaml:"prometheus" mapstructure:"prometheus"`
	Otel                  Otel           `yaml:"otel" mapstructure:"otel"`
	Plugs                 map[string]any `yaml:"plugs" mapstructure:"plugs"`
	OtherConfig           any            `yaml:"other_config" mapstructure:"other_config"`
}

type Log struct {
	Level     string `yaml:"level" mapstructure:"level"`
	WriteType int    `yaml:"write_type" mapstructure:"write_type"`
	LogPath   string `yaml:"log_path" mapstructure:"log_path"`
	Rotate    string `yaml:"rotate" mapstructure:"rotate"`     // 日志分割配置 y 年 M 月 d 日 h 时 m 分 s 秒
	Encoding  string `yaml:"encoding" mapstructure:"encoding"` // 输出格式 console、json
}

type Auth struct {
	AuthLs        []string `json:"auth_ls" mapstructure:"auth_ls"`
	Timeout       int      `json:"time_out" mapstructure:"time_out"`
	SecreKey      string   `json:"secre_key" mapstructure:"secre_key"`
	SigningMethod int      `json:"signing_method" mapstructure:"signing_method"`
	HeaderKey     string   `json:"header_key" mapstructure:"header_key"`
	CookieKey     string   `json:"cookie_key" mapstructure:"cookie_key"` // 鉴权参数也可以放入cookie中
	DisableLs     []string `json:"disable_ls" mapstructure:"disable_ls"`
}

type Mysql struct {
	Name            string `yaml:"name" mapstructure:"name"`
	Target          string `yaml:"target" mapstructure:"Target"`
	MaxIdle         int    `yaml:"max_idle" mapstructure:"max_idle"`
	MaxOpen         int    `yaml:"max_open" mapstructure:"max_open"`
	MaxLift         int    `yaml:"max_lift" mapstructure:"max_lift"`
	SkipDefaultTran bool   `yaml:"skip_default_tran" mapstructure:"skip_default_tran"` // 是否禁用默认事务
	PrepareStmt     bool   `yaml:"prepare_stmt" mapstructure:"prepare_stmt"`           // 是否开启缓存已编译sql
}

type GormLog struct {
	SlowThreshold             int  `yaml:"slow_threshold" mapstructure:"slow_threshold"`                               // 慢查询阈值，单位 ms
	Colorful                  bool `yaml:"colorful" mapstructure:"colorful"`                                           // 日志是否着色
	IgnoreRecordNotFoundError bool `yaml:"ignore_record_not_found_error" mapstructure:"ignore_record_not_found_error"` // 是否忽略记录不存在的错误
	ParameterizedQueries      bool `yaml:"parameterized_queries" mapstructure:"parameterized_queries"`                 // 不包含参数在sql log内
	LogLevel                  int  `yaml:"log_level" mapstructure:"log_level"`                                         // 1: Silent, 2: Error, 3: Warn, 4: Info
}

type Redis struct {
	RedisName  string   `yaml:"redis_name" mapstructure:"redis_name"` // redis服务的名称,使用多个不同redis
	Addrs      []string `yaml:"addrs" mapstructure:"addrs"`           // 多个地址，使用集群模式
	UserName   string   `yaml:"user_name" mapstructure:"user_name"`
	PassWord   string   `yaml:"pass_word" mapstructure:"pass_word"`
	Db         int      `yaml:"db" mapstructure:"db"`
	MasterName string   `yaml:"master_name" mapstructure:"master_name"` // 配置name，使用哨兵模式
}

type Consul struct {
	Address   string `yaml:"address" mapstructure:"address"`
	Token     string `yaml:"token" mapstructure:"token"`
	ServiceIp string `yam:"service_ip" mapstructure:"service_ip"` // consul注册服务使用真实ip，如果为空使用启动服务的ip
}

type Jaeger struct {
	Address     string `yaml:"address" mapstructure:"address"`
	AddressHTTP string `yaml:"address_http" mapstructure:"address_http"`
	EnableDB    bool   `yaml:"enable_db" mapstructure:"enable_db"`
	EnableRedis bool   `yaml:"enable_redis" mapstructure:"enable_redis"`
}
type Rabbitmq struct {
	Address    string `yaml:"address" mapstructure:"address"`
	QueueName  string `yaml:"queue_name" mapstructure:"queue_name"`
	MaxRetry   int32  `yaml:"max_retry" mapstructure:"max_retry"`
	MaxConsume int    `yaml:"max_consume" mapstructure:"max_consume"`
}

type GrpcClient struct {
	ServiceName string `yaml:"service_name" mapstructure:"service_name"`
	Tag         string `yaml:"tag" mapstructure:"tag"`
	Address     string `yaml:"address" mapstructure:"address"` // 用于直连grpc服务
}

// 解决跨域配置
type Cors struct {
	UseDefault       bool   `yaml:"use_default" mapstructure:"use_default"`
	AllowOrigins     string `yaml:"allow_origins" mapstructure:"allow_origins"`
	AllowMethods     string `yaml:"allow_methods" mapstructure:"allow_methods"`
	AllowHeaders     string `yaml:"allow_headers" mapstructure:"allow_headers"`
	ExposeHeaders    string `yaml:"expose_headers" mapstructure:"expose_headers"`
	AllowCredentials bool   `yaml:"allow_credentials" mapstructure:"allow_credentials"`
	MaxAge           int    `yaml:"max_age" mapstructure:"max_age"`
}

// 普罗米修斯配置
type Prometheus struct {
	Ip   string `yaml:"ip" mapstructure:"ip"`
	Port int    `yaml:"port" mapstructure:"port"`
	Path string `yaml:"path" mapstructure:"path"`
}

// opentelemetry 配置
type Otel struct {
	TracerHttp        string `yaml:"tracer_http" mapstructure:"tracer_http"`                 // 链路追踪配置链接
	EnableTracerDB    bool   `yaml:"enable_tracer_db" mapstructure:"enable_tracer_db"`       // 是否开启db链路追踪
	EnableTracerRedis bool   `yaml:"enable_tracer_redis" mapstructure:"enable_tracer_redis"` // 是否开启redis链路追踪
	PrometheusAddress string `yaml:"prometheus_address" mapstructure:"prometheus_address"`   // 开启普罗米斯监控 ip:port
	PrometheusRoute   string `yaml:"prometheus_route" mapstructure:"prometheus_route"`       // 开启普罗米斯监控 启动被拉取的路由
}

var fginConfig Config

func readConfig(path string) {
	viper.SetConfigType("yaml")
	viper.SetConfigFile(path)
	if err := viper.ReadInConfig(); err != nil {
		panic(err.Error())
	}

	if err := viper.Unmarshal(&fginConfig); err != nil {
		panic(err.Error())
	}
}

// 独立读取配置
func ReadConfig(path string) (Config, error) {
	fginConfigV2 := Config{}
	viper.SetConfigType("yaml")
	viper.SetConfigFile(path)
	if err := viper.ReadInConfig(); err != nil {
		return fginConfigV2, err
	}

	if err := viper.Unmarshal(&fginConfigV2); err != nil {
		return fginConfigV2, err
	}
	return fginConfigV2, nil
}

// 独立读取配置，other部分
//
//	cfgOther 需要传入指针
func ReadOtherConfig(fginConfigV2 Config, cfgOther any) error {
	oCfgB, err := json.Marshal(fginConfigV2.OtherConfig)
	if err != nil {
		return err
	}
	if err = json.Unmarshal(oCfgB, cfgOther); err != nil {
		return err
	}
	return nil
}
